package com.rrd.itext.utils;

import java.util.Iterator;

import com.thoughtworks.xstream.core.util.FastStack;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;

public class HtmlDeserializer {
	private HierarchicalStreamReader reader;
	private StringBuffer output;

	private final FastStack elementStack = new FastStack(16);

	private boolean tagInProgress;
	private boolean readyForNewLine;
	private boolean tagIsEmpty;
	private int depth;
	
	private static final String CLOSE = "</";

	public HtmlDeserializer(HierarchicalStreamReader reader) {
		this.reader = reader;
		this.output = new StringBuffer();
	}

	public String deserialize() {
		while(this.reader.hasMoreChildren()){
			this.reader.moveDown();
			// Node Name
			this.startNode(this.reader.getNodeName());
			
			// Node Attribute
			@SuppressWarnings("unchecked")
			Iterator<String> it = this.reader.getAttributeNames();
			while(it.hasNext()){
				String attr = it.next();
				this.addAttribute(attr, this.reader.getAttribute(attr));
			}
			
			// Node Value
			String value = this.reader.getValue();
			this.setValue(value);
			
			// End Node
			if(!this.reader.hasMoreChildren()){
				this.endNode();
			}
		}
		
		// End Node
		while(depth > 0){
			this.endNode();
		}

		return this.output.toString();

	}
	
	private String trim(String content) {
		String regex = "\\s*|(\r\n)";
		return content.replaceAll(regex, "");
	}

	private void startNode(String name) {
		depth++;
		tagIsEmpty = false;
		finishTag();
		this.output.append("<");
		this.output.append(name);
		this.elementStack.push(name);
		this.tagInProgress = true;
		this.readyForNewLine = true;
		this.tagIsEmpty = true;
	}
	
	public void setValue(String text) {
		readyForNewLine = false;
		tagIsEmpty = false;
		finishTag();
		if(!this.trim(text).isEmpty()){
			this.output.append(text);
		}
	}

	private void finishTag() {
		if (tagInProgress) {
			this.output.append(">");
		}
		tagInProgress = false;
		if (readyForNewLine) {
			endOfLine();
		}
		readyForNewLine = false;
		tagIsEmpty = false;
	}

	protected void endOfLine() {
		this.output.append("\n");
	}

	private void addAttribute(String key, String value) {
		this.output.append(" ");
		this.output.append(key);
		this.output.append("=");
		this.output.append("\"");
		this.output.append(value);
		this.output.append("\"");
	}

	public void endNode() {
		depth--;
		if (tagIsEmpty) {
			this.output.append("/");
			readyForNewLine = false;
			finishTag();
			elementStack.popSilently();
		} 
		else {
			finishTag();
			this.output.append(CLOSE);
			this.output.append((String) elementStack.pop());
			this.output.append('>');
		}
		readyForNewLine = true;
		if (depth == 0) {
		}
	}

	public HierarchicalStreamReader getReader() {
		return reader;
	}

	public void setReader(HierarchicalStreamReader reader) {
		this.reader = reader;
	}

	public StringBuffer getOutput() {
		return output;
	}

	public void setOutput(StringBuffer output) {
		this.output = output;
	}

}
